package com.iocup.keybastion.authorize.decision;


import com.iocup.keybastion.authorize.element.AuthElement;
import com.iocup.keybastion.context.WebContextHolder;
import com.pine.sunflower.core.validate.Validator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.List;

/**
 * Basic认证决断器
 *
 * @author xyjxust
 * @create 2022/2/28 17:25
 **/
public class BasicAuthDecision implements AuthDecision {

    private static final String USER_NAME = "username";
    private static final String PASSWORD = "password";
    private BasicProperties basicProperties;

    public BasicAuthDecision(BasicProperties basicProperties) {
        Validator.build()
                .validate(basicProperties == null, "basicProperties不能为空")
                .validate(basicProperties.isEnabled() && (StringUtils.isEmpty(basicProperties.getUserName()) ||
                        StringUtils.isEmpty(basicProperties.getPassword())), "basic已启用全局认证，但是账号和密码为空")
                .throwIfFail();
        this.basicProperties = basicProperties;
    }

    @Override
    public boolean decide(List<AuthElement> list, WebContextHolder webContext) {
        //如果basic认证没有启动就通过
        if (!this.basicProperties.isEnabled()) {
            return true;
        }
        //获取header中的basic信息
        String token = webContext.getRequestHeader(this.basicProperties.getHeaderName()).orElse("");
        //传入的为空那肯定就是不通过了
        if (StringUtils.isEmpty(token)) {
            return false;
        }
        //如果在启用下且权限元素为空，那么表示此时是全局启用认证，判断该token是否和配置类中的用户名和密码是否一致
        if (this.basicProperties.isEnabled() && CollectionUtils.isEmpty(list)
                && !encodeString(this.basicProperties.getUserName(), this.basicProperties.getPassword()).equals(token)) {
            return false;
        }
        //否则就验证url或者method下的basic注解
        return list.stream().filter(el -> StringUtils.isNotEmpty(el.getParam(USER_NAME)) && StringUtils.isNotEmpty(el.getParam(PASSWORD)))
                .anyMatch(el -> !encodeString(el.getParam(USER_NAME), el.getParam(PASSWORD)).equals(token));
    }

    @Override
    public String getType() {
        return DecisionType.basic.name();
    }


    private String encodeString(String userName, String password) {
        try {
            return Base64.getEncoder().encodeToString((userName
                    + ":" + password).getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new SecurityException("编码basic认证信息错误");
        }
    }
}
